/* 
 * Created on 9. September 2008, 01:08
 *
 *      Copyright 2008 Oliver Eichner <o.eichner@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 3 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#include <gtkmm-2.4/gtkmm/treeview.h>


/**
 * @file DeviceTreeView.cpp
 * TreeView widget for the mainwindow
 */

#include "DeviceTreeView.h"
#include "DeviceDetailDialog.h"
#include "text.h"

/**
 * @brief Gtk TreeView for the Devices (HDDs)
 * Creates a Treeview withvendor,model,size etc..
 */
DeviceTreeView::DeviceTreeView() {
    create_model();

    //Fill popup menu:
    {
        Gtk::Menu::MenuList& menulist = tp_Menu_Popup.items();

        menulist.push_back(Gtk::Menu_Helpers::MenuElem("_Details",
                sigc::mem_fun(*this, &DeviceTreeView::on_menu_file_popup_Details)));
        menulist.push_back(Gtk::Menu_Helpers::MenuElem("_Add Comment",
                sigc::mem_fun(*this, &DeviceTreeView::on_menu_file_popup_AddComment)));
        menulist.push_back(Gtk::Menu_Helpers::MenuElem("_Save",
                sigc::mem_fun(*this, &DeviceTreeView::on_menu_file_popup_Save)));
       // menulist.push_back(Gtk::Menu_Helpers::MenuElem("_Print",
         //       sigc::mem_fun(*this, &DeviceTreeView::on_menu_file_popup_Print)));

    }
    tp_Menu_Popup.accelerate(*this);

}

DeviceTreeView::DeviceTreeView(const DeviceTreeView& orig) {
}

DeviceTreeView::~DeviceTreeView() {
}

/**
 * @brief Destroy and Reload the Treeview
 */
void DeviceTreeView::reload() {
    remove_all_columns();

    create_model();

}

/**
 * @brief Creates hte TreeView model
 */
void DeviceTreeView::create_model() {
    tp_refListStore = Gtk::ListStore::create(tp_Columns);

    // set_model(tp_refTreeModel);
    add_items();

    std::for_each(
            tp_vecItems.begin(), tp_vecItems.end(),
            sigc::mem_fun(*this, &DeviceTreeView::liststore_add_item));
    set_model(tp_refListStore);
    set_rules_hint();
    add_columns();
}

/**
 * @brief Adds all Devices, beginning with "sd*" in /proc/partitions as Item
 * into the TreeView
 */
void DeviceTreeView::add_items() {
    fstream PartFile;
    string newDevice, oldDevice;
    int len, sdPos;
    DeviceList.clear();
    PartFile.open("/proc/partitions", ios::in);
    tp_vecItems.clear();
    while (!PartFile.eof() && !PartFile.fail()) {
        getline(PartFile, newDevice);
        len = newDevice.length();
        sdPos = newDevice.find("sd");
        //cout<<"sdPos:"<<sdPos<<endl;
        if (sdPos != -1)
            newDevice.erase(sdPos + 3, len);
        newDevice.erase(0, sdPos);


        if (!newDevice.empty() && oldDevice != newDevice) {
            oldDevice = newDevice;
            Device deviceInfo(newDevice);
            DeviceList.push_back(deviceInfo);


        }
    }
    PartFile.close();

    //iterate over deviceList and fill tree..
    //fill tree
    for (list<Device>::iterator iter = DeviceList.begin(); iter != DeviceList.end(); iter++) {

        tp_vecItems.push_back(CellItem_Device(
                (!iter->getBridge_model().empty() ? iter->getBridge_model() : "local"),
                iter->getDeviceName(),
                iter->getVendor(),
                iter->getModel(),
                iter->getSize(),
                iter->getBridge_declare_write_blocked(),
                iter->getBridge_hpa_in_use(),
                iter->getBridge_dco_in_use(),
                iter->getBridge_security_in_use())
                );
        cout << "text: " << iter->getModel() << endl;
    }
}

/**
 * @brief ListStore helper to fill the Item Information into the TreeView
 * @param tp_items A CellItem_Device Object
 */
void DeviceTreeView::liststore_add_item(const CellItem_Device& tp_items) {
    Gtk::TreeRow row = *(tp_refListStore->append());

    row[tp_Columns.tp_col_tbridge] = tp_items.tp_tbridge;
    row[tp_Columns.tp_col_devname] = tp_items.tp_devicename;
    row[tp_Columns.tp_col_vendor] = tp_items.tp_vendor;
    row[tp_Columns.tp_col_model] = tp_items.tp_model;
    row[tp_Columns.tp_col_size] = tp_items.tp_size;
    row[tp_Columns.tp_col_writeblocked] = tp_items.tp_writeblocked;
    row[tp_Columns.tp_col_hpa_inUse] = tp_items.tp_hpa_inUse;
    row[tp_Columns.tp_col_dco_inUse] = tp_items.tp_dco_inUse;
    row[tp_Columns.tp_col_security_inUse] = tp_items.tp_security_inUse;
}

/**
 * @brief Add the Columns into the TreeView
 */
void DeviceTreeView::add_columns() {
    /* column for fixed toggles */

    append_column("Bridge", tp_Columns.tp_col_tbridge);
    append_column("Device", tp_Columns.tp_col_devname);
    append_column("Vendor", tp_Columns.tp_col_vendor);

    append_column("Model", tp_Columns.tp_col_model);
    append_column("Size", tp_Columns.tp_col_size);
    append_column("Writeblocked", tp_Columns.tp_col_writeblocked);

    append_column("HPA in use", tp_Columns.tp_col_hpa_inUse);
    append_column("DCO in use", tp_Columns.tp_col_dco_inUse);
    append_column("Security in use", tp_Columns.tp_col_security_inUse);

    // 2farbige zeilen!!
    set_rules_hint();
    // sortieren von spalten
    Gtk::TreeView::Column* pColumn = get_column(1);
    if (pColumn) {
        pColumn->set_sort_column(tp_Columns.tp_col_devname);

        //column text farbig machen
        //        Gtk::CellRendererText* renderer = static_cast<Gtk::CellRendererText*>(pColumn->get_first_cell_renderer());
        //       renderer->property_foreground_gdk().set_value(Gdk::Color("green"));
    }

}

/**
 * @brief popup on right click at a row
 * @param event Gdkevent..
 * @return bool
 */
bool DeviceTreeView::on_button_press_event(GdkEventButton* event) {
    //Call base class, to allow normal handling,
    //such as allowing the row to be selected by the right-click:
    bool return_value = TreeView::on_button_press_event(event);

    //Then do our custom stuff:
    if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
        tp_Menu_Popup.popup(event->button, event->time);
    }

    // if middle mouse button is pressed
    if ((event->type == GDK_BUTTON_PRESS) && (event->button == 2)) {
        cout<<"middle click: "<<endl;
    }
    // if left mouse button is pressed
    if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
        cout<<"left click: "<<endl;
    }
    if((event->type == 5) && (event->button == 1)) {
        cout<<"double click left: "<<endl;
        on_menu_file_popup_Details();
    }


    return return_value;
}

/**
 * @brief Generic Fuction to for popup action.. 
 * just for testings!!!
 */
void DeviceTreeView::on_menu_file_popup_generic() {
    std::cout << "A popup menu item was selected." << std::endl;

    Glib::RefPtr<Gtk::TreeView::Selection> refSelection = get_selection();
    if (refSelection) {
        Gtk::TreeModel::iterator iter = refSelection->get_selected();
        if (iter) {
            //string device_id=(*iter)[tp_Columns.tp_col_devname];
            std::cout << "  Selected Device=" << (*iter)[tp_Columns.tp_col_devname] << std::endl;
        }
    }
}

/**
 * @brief Popup action for the Detail View
 * Opens a dialog with Detailed Informations about the selected Disk
 */
void DeviceTreeView::on_menu_file_popup_Details() {
    cout << "Popup Details Selected" << std::endl;

    if (somethingSelected()) {

        DeviceDetailDialog* ddDialog = new DeviceDetailDialog(get_SelectedDeviceIterator());
        int res = ddDialog->run();
        //cout << "exit id:" << res << endl;
        delete ddDialog;

        switch (res) {
            case response_Save:
                //cout << "response save" << endl;
                on_menu_file_popup_Save();

                break;
            case response_Print:
                cout << "print not implemented" << endl;
                break;
        }
    }

}

/**
 * @brief Popup action for save purpose
 * opens a filechosser dialog
 */
void DeviceTreeView::on_menu_file_popup_Save() {
    cout << "Popup Save Selected" << std::endl;

    if (somethingSelected()) {
        //dialogSaveTo(deviceIter);
        SaveToFileDialog saveDialog(get_SelectedDeviceIterator());
        int result = saveDialog.run();
        switch (result) {

            case(Gtk::RESPONSE_OK) : {
                    cout << "Save clicked." << std::endl;

                    //check if extension is .txt
                    string filename = saveDialog.get_Filename();
                    //string ext = saveDialog.get_filter()->get_name();
                    cout << "File selected: " << filename << endl;
                    //cout << "Filetype: " << ext << endl;
                    saveDialog.saveTo(filename, get_SelectedDeviceIterator());
                    break;
                }

            case(Gtk::RESPONSE_APPLY) : {
                    cout << "Add Comment clicked." << endl;
                    saveDialog.hide();
                    on_menu_file_popup_AddComment();
                    on_menu_file_popup_Save();
                    break;
                }

            case(Gtk::RESPONSE_CANCEL) : {
                    cout << "Cancel clicked." << std::endl;
                    break;
                }
            default:
            {
                std::cout << "Unexpected button clicked." << std::endl;
                break;
            }

        }

    }

}

/**
 * @brief Popup action for add comments
 */
void DeviceTreeView::on_menu_file_popup_AddComment() {
    cout << "Popup Comment Selected" << std::endl;

    if (somethingSelected()) {

        CommentDialog comDiag(get_SelectedDeviceIterator());
        int result = comDiag.run();
        cout << "comment exit id:" << result << endl;

        switch (result) {

            case(Gtk::RESPONSE_OK) : {

                    cout << "OK clicked" << endl;
                    get_SelectedDeviceIterator().setComment(comDiag.getText());
                    break;

                }

            case(Gtk::RESPONSE_CANCEL) : {
                    cout << "Cancel clicked." << std::endl;
                    break;
                }
            default:
            {
                std::cout << "Unexpected button clicked." << std::endl;
                break;
            }

        }// end switch

    }

}

/**
 * @brief Popup action for printing
 *
 */
void DeviceTreeView::on_menu_file_popup_Print() {

}

/**
 * @brief Search in the DeviceList for a specific device#
 * @param devine kernelname
 * @return the iterator pointer to the listplace
 */

list<Device>::iterator DeviceTreeView::findDeviceIter(Glib::ustring deviceName) {
    for (list<Device>::iterator iter = DeviceList.begin(); iter != DeviceList.end(); iter++) {
        if (iter->getDeviceName() == deviceName) {
            return iter;
        }
    }
    return DeviceList.end();
}

/**
 * @brief Dialog for printing device informations
 * @param list iterator of DevieList
 */
void DeviceTreeView::dialogPrint(list<Device>::iterator nDeviceIter) {

}

void DeviceTreeView::hideColumn(DevTreeEnum column) {
    Gtk::TreeView::Column* pColumn;
    pColumn = get_column(column);
    if (pColumn) {
        if (pColumn->get_visible())
            pColumn->set_visible(false);
        else
            pColumn->set_visible(true);
    }
}

/**
 * @brief check if something is selected, in the treeview
 * @return true if something is selected
 */
bool DeviceTreeView::somethingSelected() {
    Glib::RefPtr<Gtk::TreeView::Selection> refSelection = get_selection();
    
    if (refSelection) {
        Gtk::TreeModel::iterator iter = refSelection->get_selected();
        if (iter) {
            return true;
        } else {
            return false;
        }
    }
    return false;
}

Device& DeviceTreeView::get_SelectedDeviceIterator() {
    Glib::RefPtr<Gtk::TreeView::Selection> refSelection = get_selection();
    if (refSelection) {
        Gtk::TreeModel::iterator iter = refSelection->get_selected();
        if (iter) {
            cout << "  Selected Device=" << (*iter)[tp_Columns.tp_col_devname] << std::endl;
            Glib::ustring devname = (*iter)[tp_Columns.tp_col_devname];
            list<Device>::iterator deviceIter = findDeviceIter(devname);
            return *deviceIter;
        }
    }
}

/**
 * @brief Default Construktor for CellItems in the TreeView
 */
CellItem_Device::CellItem_Device() {

    tp_dco_inUse = false;
    tp_hpa_inUse = false;
    tp_security_inUse = false;
    tp_writeblocked = false;
}

/**
 * @brief Construktor for CellItems in the TreeView
 * @param tbridge Bridgename
 * @param devicename Kernel-Devicename
 * @param vendor Vendor
 * @param model Model
 * @param size size
 * @param writeblocked writeblocked true/false
 * @param hpa_inUse hpa in use
 * @param dco_inUse dco in use
 * @param security_inUse security in use
 */
CellItem_Device::CellItem_Device(string tbridge, string devicename,
        string vendor, string model,
        string size, bool writeblocked, bool hpa_inUse,
        bool dco_inUse, bool security_inUse) {

    tp_tbridge = tbridge;
    tp_devicename = devicename;
    tp_vendor = vendor;
    tp_model = model;
    tp_size = size;
    tp_writeblocked = writeblocked;
    tp_hpa_inUse = hpa_inUse;
    tp_dco_inUse = dco_inUse;
    tp_security_inUse = security_inUse;
}

/**
 * @brief Copy Constructor for CellItems
 * @param CekkItem_Device the source object
 */
CellItem_Device::CellItem_Device(const CellItem_Device & src) {

    operator=(src);
}

/**
 * @brief default Destructor for CellItems
 */
CellItem_Device::~CellItem_Device() {

}

/**
 * @brief operator overload for direct set
 * @param CellItem_Device the source object
 */
CellItem_Device & CellItem_Device::operator =(const CellItem_Device & src) {
    tp_tbridge = src.tp_tbridge;
    tp_devicename = src.tp_devicename;
    tp_vendor = src.tp_vendor;
    tp_model = src.tp_model;
    tp_size = src.tp_size;
    tp_writeblocked = src.tp_writeblocked;
    tp_hpa_inUse = src.tp_hpa_inUse;
    tp_dco_inUse = src.tp_dco_inUse;
    tp_security_inUse = src.tp_security_inUse;
    return *this;
}
